package org.nf.web.servlet;

import cn.hutool.core.exceptions.ExceptionUtil;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.nf.web.adapter.SimpleHandlerAdapter;
import org.nf.web.config.Configure;
import org.nf.web.mapping.MethodHanlerMapping;
import org.nf.web.mapping.SimpleHandlerMapping;
import org.nf.web.view.DefaultView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;

/**
 * @Author lzp
 * @Date 2024-05-14
 * 请求总控器,负责接受所有的请求，然后根据请求的地址
 * 分发给不同的后端控制器（Controller）
 * 当url-pattern设置为"/"时，会覆盖默认的DefaultServlet
 * 所有的web服务器都会有一个默认的Servlet,这个Servlet
 * 专门用于处理静态资源
 */
public class DispatcherServlet extends HttpServlet {

    /**
     *HandlerMapping集合,负责查找Controller
     */
    private List<HandlerMapping> handlerMappings = new ArrayList<>();

    /**
     * HandlerAdapter集合,负责调用Controller
     */
    private List<HandlerAdapter> handlerAdapters = new ArrayList<>();

    /**
     * 异常解析器集合
     */
    private List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext sc = config.getServletContext();
        //获取从servletContext中获取配置对象
        Configure configure = (Configure) sc.getAttribute("configure");
        //初始化HandlerMapping
        initHandlerMapping(configure);
        //初始化Handler
        initHandlerAdapter();
        //初始化异常解析器
        initExceptionResolver(configure);
    }

    /**
     * 初始化所有的HandlerAdapter
     */
    private void initHandlerAdapter(){
        for (HandlerAdapter adapter : ServiceLoader.load(HandlerAdapter.class)){
            handlerAdapters.add(adapter);
        }
    }

    /**
     * 初始化HandlerMapping
     */
    private void initHandlerMapping(Configure configure){
        for (HandlerMapping hm : ServiceLoader.load(HandlerMapping.class)){
            hm.init(configure);
            handlerMappings.add(hm);
        }
    }

    /**
     * 初始化异常解析器
     * @param configure 配置对象
     */
    private void initExceptionResolver(Configure configure){
        for (HandlerExceptionResolver resolver
                : ServiceLoader.load(HandlerExceptionResolver.class)){
            resolver.init(configure);
            exceptionResolvers.add(resolver);
        }
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletApi servletApi = new ServletApi(req,resp);
        //根据请求获取对应的handler
        Object handler = getHandler(req);
        //如果controller不为null则交给HandlerInvoke去调用
        if (handler != null){
            //将handler交给HandlerInvoke负责调用
            //找到合适匹配的adapter
            HandlerAdapter ha = getAdapter(handler);
            Object viewObj;
            try {
                //调用handler方法处理请求,并返回视图
                viewObj = ha.handler(handler,servletApi);
                //渲染视图
                render(viewObj,servletApi);
            } catch (Exception e) {
                //处理全局异常
                viewObj = handlerException(e);
            }
            //渲染视图
            render(viewObj,servletApi);
        }else {
            //将其他的请求都转发容器默认的Servlet处理
            //根据Servlet名称进行转发
            req.getServletContext().getNamedDispatcher("default").forward(req,resp);
        }
    }

    /**
     * 根据HandlerMapping查找合适的handler子类
     * 这个handler可能是Class也可能是Method对象
     * @param req
     * @return
     */
    private Object getHandler(HttpServletRequest req){
        for (HandlerMapping mapping : handlerMappings){
            Object handler = mapping.getHandler(req);
            if (handler != null){
                return handler;
            }
        }
        return null;
    }

    /**
     * 根据handler找到合适的适配器
     * @param handler
     * @return
     */
    private HandlerAdapter getAdapter(Object handler){
        for (HandlerAdapter adapter :handlerAdapters){
            if (adapter.supports(handler)){
                return adapter;
            }
        }
        throw new RuntimeException("HandlerAdapter not found.");
    }

    /**
     * 异常处理
     * @param e 产生的异常
     * @return 视图
     */
    private View handlerException(Exception e){
        //现获取真正引发的异常对象
        Throwable t = ExceptionUtil.getRootCause(e);
        t.printStackTrace();
        View view = null;
        //只要有一个异常解析器可以解析成功就跳出循环
        for (HandlerExceptionResolver resolver : exceptionResolvers ){
            view = resolver.resolveException(t);
            if (view !=null){
                break;
            }
        }
        return view;
    }

    /**
     * 渲染视图对象
     * @param object 由适配器返回的视图对象
     */
    private void render(Object object,ServletApi api)
            throws ServletException,IOException{
        if (object != null){
            //如果是View接口的实例,则强转后执行渲染
            //否则使用默认的视图来处理响应
            if (object instanceof View view){
                view.render(api);
            }else {
                new DefaultView(object).render(api);
            }
        }
    }

}
